import os
import time
import winreg
import json
import ctypes


def get_documents_path():
    try:
        # 打开注册表项
        key = winreg.OpenKey(
            winreg.HKEY_CURRENT_USER,
            r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
        )
        # 读取文档路径键值
        documents_path = winreg.QueryValueEx(key, "Personal")[0]
        # 关闭注册表项
        winreg.CloseKey(key)
        return documents_path
    except OSError as e:
        print(f"获取文档路径出错: {e}")
        return None


def broadcast_setting_change():
    # 通知所有的进程刷新它们的环境变量。在Windows上，发送一个 WM_SETTINGCHANGE 消息给所有的顶级窗口
    HWND_BROADCAST = 0xFFFF
    WM_SETTINGCHANGE = 0x1A
    SMTO_ABORTIFHUNG = 0x0002
    result = ctypes.windll.user32.SendMessageTimeoutW(
        HWND_BROADCAST, WM_SETTINGCHANGE, 0, "Environment", SMTO_ABORTIFHUNG, 5000, None
    )
    if result == 0:
        raise ctypes.WinError()


class EnvVariables:
    """ 环境变量 """

    def __init__(self, is_all_user=True):
        self.is_all_user = is_all_user
        self.hkey = (
            winreg.HKEY_LOCAL_MACHINE if is_all_user else winreg.HKEY_CURRENT_USER
        )
        self.sub_key = (
            r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
            if is_all_user
            else r"Environment"
        )
        self.registry_env_key = winreg.OpenKey(
            self.hkey, self.sub_key, 0, winreg.KEY_ALL_ACCESS
        )
        self.env_variables = {}
        self.get_all_env_variables()
        self.backup_file = None
        self.path_value = self.get_variable("Path")

    def __str__(self):
        return (
            f"EnvVariables(\n"
            f"  key={self.hkey},\n"
            f"  sub_key={self.sub_key},\n"
            f"  registry_env_key={self.registry_env_key},\n"
            f"  env_variables={self.env_variables},\n"
            f"  path_value={self.path_value},\n"
            f"  backup_file={self.backup_file}\n"
            f")"
        )

    def backup_env_variables(self):
        """ 备份环境变量 """
        self.backup_file = self.create_backup_file()
        with open(self.backup_file, "w") as f:
            json.dump(self.env_variables, f)

    def create_backup_file(self):
        """ 创建备份文件 """
        documents_path = get_documents_path()
        if documents_path is None:
            raise OSError("获取文档路径出错")
        env_backup_path = os.path.join(documents_path, "DevEnvMaster", "env_backup")
        os.makedirs(env_backup_path, exist_ok=True)  # 判断是否存在env_backup文件夹，不存在则创建
        return os.path.join(
            env_backup_path,
            f"env_backup_{int(self.is_all_user)}__{time.strftime('%Y%m%d%H%M%S', time.localtime())}.json",
        )

    def add_path_value(self, args, at_end=False):
        """ 在path变量的值前面/后面添加value """
        self.path_value = self.get_variable("Path")
        path_value_list = self.path_value.split(";")
        # 移除path_value_list中已经存在的args元素
        path_value_list = [value for value in path_value_list if value not in args]

        # 将args添加到path_value_list前面/后面
        if at_end:
            new_path_value_list = path_value_list + args
        else:
            new_path_value_list = args + path_value_list

        new_path_value_str = ";".join(new_path_value_list)
        # print("更新path变量的值：", new_path_value_str)
        self.backup_env_variables()
        self.update_path_value(new_path_value_str)

    def refresh_env(self):
        """ 刷新环境变量 """
        broadcast_setting_change()

    def update_path_value(self, value):
        """ 更新path变量的值 """
        winreg.SetValueEx(
            self.registry_env_key, "Path", 0, winreg.REG_SZ, value
        )
        self.refresh_env()

    def get_variable(self, name):
        """ 根据变量名获取变量值 """
        return self.env_variables.get(name, None)

    def create_variable(self, name, value):
        """ 创建变量 """
        self.backup_env_variables()
        self.env_variables[name] = value
        winreg.SetValueEx(
            self.registry_env_key, name, 0, winreg.REG_SZ, value
        )
        self.refresh_env()

    def get_all_env_variables(self):
        """ 获取所有环境变量 """
        i = 0
        while True:
            try:
                name, value, _ = winreg.EnumValue(self.registry_env_key, i)
                self.env_variables[name] = value
                i += 1
            except OSError:
                break
